from panda3d.core import Vec2,Point3,Vec3,Vec4
import math
import copy
from pandac.PandaModules import TextureStage
from direct.interval.IntervalGlobal import *
'''
	Andrew Oberlin, Michael Jacobs, Tom Williams
	Date: February 7, 2012
	
	Model Class declaration
'''
class Enemy:
	'''
		Constructor for the model abstract class
	'''
	def __init__(self, parent, mapIndex, name):
		self.parent = parent
		self.prevTime = 0
		self.mapIndex = mapIndex
		self.name = name
		self.alive = True
		self.loadModel()
		self.velocity = Vec2(0, 0)
		self.acceleration = Vec2(0,0)
		self.walkingTask = self.parent.taskMgr.add(self.walk, name + "_walk")
		self.walkingTask.fps = 4
		self.WALK_SPEED = 30
		self.velocity[0] = self.WALK_SPEED;
	
		
		self.height = self.parent.BLOCK_SIZE
		self.width = self.parent.BLOCK_SIZE
		
	'''
		Loads the Goomba Model
	'''
	def loadModel(self):
		self.loadTexture()
		self.set2DProps()
		
	'''
		Creates the plane and the texture
		
		Overwrite this in the subclasses of MarioActor to load correct model
	'''
	def loadTexture(self):
		self.model = self.parent.loader.loadModelCopy("models/plane")
		self.textures = self.loadTextureMovie(2, 'models/characters/enemies/goomba', 'png') 
		#self.texture = self.parent.loader.loadTexture("models/characters/enemies/goomba_1.png")
		
	'''
		Sets the properties for a two dimensional figure
	'''
	def set2DProps(self):
		self.model.setHpr(Vec3(0,-90,0))
		self.model.setScale(self.parent.BLOCK_SIZE)
		
		# maximize efficiency
		self.model.setBin("unsorted", 0)
		self.model.setDepthTest(False)
		self.model.setTransparency(1)
		
		#self.model.setTexture(self.texture)
		self.model.reparentTo(render)
		
	'''
		Our custom load function to load the textures needed for a movie into a
		list. It assumes the the files are named
		"path/name<serial number>.extention"
		
		Params: frames -- The number of frames to load
				name -- The "path/name" part of the filename path
				suffix -- The "extention" part of the path
				padding -- The number of digit the serial number contians:
					e.g. if the serial number is 0001 then padding is 4
	'''
	def loadTextureMovie(self, frames, name, suffix, padding = 1):
		return [loader.loadTexture((name+"_%0"+str(padding)+"d."+suffix) % i) for i in range(frames)]
	
	'''
		Runs the task to animate the sprite as walking
	'''
	def walk(self, task):
		if (self.alive):
			#change the model's texture to match direction
			direction = int(self.velocity[0] / math.fabs(self.velocity[0]))
			scale = self.model.getTexScale(TextureStage.getDefault())
			self.model.setTexScale(TextureStage.getDefault(), math.fabs(scale[0])*direction, scale[1])		
		
			#Here we calculate the current frame number by multiplying the current time
			#(in seconds) by the frames per second variable we set earlier
			currentFrame = int(task.time * task.fps)
			delta_t = task.time - self.prevTime
			self.prevTime = task.time
			
			self.model.setTexture(self.textures[currentFrame % len(self.textures)], 1)
			
			#Keep within level bounds
			tmp_vel = copy.deepcopy(self.velocity)
			if (self.model.getX() + self.width/2.0 >= self.parent.level.width - 5 and tmp_vel[0] > 0):
				tmp_vel[0] = 0
			elif (self.model.getX() - self.width/2.0 <= 5 and tmp_vel[0] < 0):
				tmp_vel[0] = 0			
			
			#Check if edge of 
			(y,x) = self.convertPosToMapCell(0.5*self.width, 0)
			if(direction == 1):
				direction = 0
			if(self.parent.level.map[y-1][x+direction].block.type == 'AIR'):
				self.velocity[0] *= -1
			elif(self.parent.level.map[y][x+direction].block.type != 'AIR'):
				self.velocity[0] *= -1
				
			(y,x) = self.convertPosToMapCell(0, 0)
			
			self.model.setPos(self.model.getPos() + Vec3(tmp_vel[0]*delta_t, tmp_vel[1]*delta_t, 0))
			
			(ny, nx) = self.convertPosToMapCell(0, 0)
			if( ny != y or nx != x ):
				self.parent.level.map[y][x].enemies.remove(self)
				self.parent.level.map[ny][nx].enemies.append(self)
				
			return task.cont 
		else:
			return task.done
	
	def convertPosToMapCell(self, offsetX, offsetY):
		pos = self.model.getPos()
		return (int((pos[1] + offsetY)/self.parent.BLOCK_SIZE), int((pos[0]+offsetX)/self.parent.BLOCK_SIZE))
	
	'''
		Starts the dying animation for this mario character
	'''
	def startDieAnimation(self):
		self.alive = False
		
		deathSequence = Parallel(
			Sequence(
				self.model.posInterval(0.15, 
					Vec3(self.model.getX() - self.parent.BLOCK_SIZE*0.5, self.model.getY() + self.parent.BLOCK_SIZE*0.5, 0)
				),
				self.model.posInterval(0.35, 
					Vec3(self.model.getX(), -self.parent.BLOCK_SIZE, 0)
				)
			),
			self.model.hprInterval(0.4, Vec3(self.model.getHpr() + Vec3(0,0,180)))
		)
		
		deathSequence.start()
		
	'''
		Removes the block from the Panda3D render and destroys the block
	'''
	def destroy(self):
		self.alive = False;
		self.model.removeNode()
		
'''
	A subclass of the MarioActor (or Goomba class) that represents a turtle
'''
class Turtle(Enemy):
	'''
		Creates the plane and the texture
		
		Overwrite this in the subclasses of MarioActor to load correct model
	'''
	def loadTexture(self):
		self.model = self.parent.loader.loadModelCopy("models/plane")
		self.textures = self.loadTextureMovie(2, 'models/characters/enemies/turtle_green_left', 'png')


